package com.koron.order.risk.base.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.BiMap;
import cn.hutool.poi.excel.WorkbookUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.koron.bean.base.Response;
import com.koron.bean.query.PageQuery;
import com.koron.bean.workflow.RedirectQuery;
import com.koron.bean.workflow.WorkflowController;
import com.koron.common.core.business.common.service.TOrderNoMaxService;
import com.koron.common.core.business.datadict.utils.DataDictTool;
import com.koron.common.core.business.workflow.templates.WorkFlowHandler;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.EasyExcelUtils;
import com.koron.order.risk.base.bean.convertor.LineRiskConvertor;
import com.koron.order.risk.base.bean.dto.LineRiskDTO;
import com.koron.order.risk.base.bean.param.LineRiskCancelParam;
import com.koron.order.risk.base.bean.query.LineRiskQuery;
import com.koron.order.risk.base.bean.vo.*;
import com.koron.order.risk.base.excel.ErrorFillRowWriteHandler;
import com.koron.order.risk.base.excel.RiskAutoConvertor;
import com.koron.order.risk.base.excel.RiskExcelListener;
import com.koron.order.risk.base.excel.RiskStringStringConvertor;
import com.koron.order.risk.base.service.LineRiskService;
import com.koron.order.risk.util.LineRiskConstant;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.koron.ebs.mybatis.ADOConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 风险管控单(LineRisk)表控制层
 *
 * @author jzp
 * @since 2022-12-15 16:17:58
 */
@Slf4j
@Api(tags = "风险管控单接口")
@RestController
@RequestMapping("lineRisk")
public class LineRiskController implements WorkflowController {

    @Autowired
    private LineRiskService lineRiskService;
    @Autowired
    private WorkFlowHandler workFlowHandler;
    @Autowired
    private LineRiskConvertor lineRiskConvertor;
    @Autowired
    private TOrderNoMaxService tOrderNoMaxService;

    private String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    @ApiOperation(value = "根据id查询基本信息")
    @GetMapping
    public Response<LineRiskVO> selectOne(@RequestParam String id) {
        return Response.ok(ADOConnection.runTask(getCurrDs(), lineRiskService, "getById", LineRiskVO.class, id));
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @ApiOperation(value = "根据id查询详情页")
    @GetMapping("detail")
    public Response<LineRiskDTO> selectDetail(@RequestParam String id) {
        return Response.ok(ADOConnection.runTask(getCurrDs(), lineRiskService, "getDtoById", LineRiskDTO.class, id));
    }

    @ApiOperation(value = "分页查询")
    @GetMapping("page")
    public Response<PageInfo<LineRiskVO>> page(PageQuery pageQuery, LineRiskQuery query) {
        return Response.ok(ADOConnection.runTask(getCurrDs(), lineRiskService, "page", PageInfo.class, pageQuery, query));
    }

    @ApiOperation(value = "保存")
    @PostMapping("save")
    public Response<LineRiskDTO> save(@RequestBody LineRiskDTO lineRiskDTO) {
        return Response.ok(ADOConnection.runTask(getCurrDs(), lineRiskService, "saveDto", LineRiskDTO.class, lineRiskDTO));
    }

    @ApiOperation(value = "作废")
    @PostMapping("cancel")
    public Response<Boolean> cancel(@RequestBody LineRiskCancelParam param) {
        return Response.ok(ADOConnection.runTask(getCurrDs(), lineRiskService, "cancel", Boolean.class, param));
    }

    @ApiOperation(value = "删除")
    @DeleteMapping("delete")
    public Response delete(@RequestParam String id) {
        ADOConnection.runTask(getCurrDs(), lineRiskService, "deleteById", Boolean.class, id);
        workFlowHandler.delete(id);
        return Response.ok();
    }

    @SneakyThrows
    @ApiOperation(value = "下载模板")
    @GetMapping("template")
    public void template(HttpServletResponse response) {
        String path = "excel/risk_import.xlsx";
        ClassPathResource classPathResource = new ClassPathResource(path);
        Workbook book = WorkbookUtil.createBook(classPathResource.getInputStream());
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("风险管控单", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        book.write(response.getOutputStream());
    }

    @SneakyThrows
    @ApiOperation(value = "导入")
    @PostMapping("import")
    public Response importFile(@RequestParam("file") MultipartFile file) {
        RiskStringStringConvertor riskStringStringConvertor = new RiskStringStringConvertor();
        RiskExcelListener riskExcelListener = new RiskExcelListener(lineRiskService, lineRiskConvertor, tOrderNoMaxService);
        EasyExcel.read(file.getInputStream(), LineRiskExcel.class, riskExcelListener)
                .registerConverter(riskStringStringConvertor)
                .headRowNumber(1)
                .sheet(0)
                .doRead();
        if (riskExcelListener.getExcelErrors().size() != 0) {
            String path = "excel/risk_import_error.xlsx";
            ClassPathResource classPathResource = new ClassPathResource(path);
            // 输出错误文件
            String filename = CodeTools.getCodeNo("RiskFile", 3);
            String tempPath = EasyExcelUtils.createTempFile(filename, "xlsx");
            log.warn("导入失败，错误文件在：{}", tempPath);
            EasyExcel.write(tempPath)
                    .withTemplate(classPathResource.getInputStream())
                    .head(LineRiskExcel.class)
                    .needHead(false)
                    .registerConverter(riskStringStringConvertor)
                    .registerWriteHandler(new ErrorFillRowWriteHandler(riskExcelListener.getExcelErrors()))
                    .sheet(0)
                    .doWrite(riskExcelListener.getErrorRisk());
            return Response.ok("temp/" + filename + ".xlsx");
        }
        return Response.ok("导入成功", null);
    }

    @SneakyThrows
    @ApiOperation(value = "导出", notes = "根据条件导出查询出的所有数据")
    @GetMapping("export")
    public void exportFile(HttpServletResponse response, LineRiskQuery query) {
        String path = "excel/risk_export.xlsx";
        ClassPathResource classPathResource = new ClassPathResource(path);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("风险管控单", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        List<LineRiskDTO> list = ADOConnection.runTask(getCurrDs(), lineRiskService, "listDetail", List.class, query);

        // 管控措施 riskLevel
        BiMap<String, String> controlMeasuresMap = new BiMap<>(DataDictTool.getDataDictByCode("transmissionRiskControl", "risk_control_measures"));

        // 获取excel数据
        List<LineRiskBuildingExcel> lineRiskDetailBuildingExcel = new ArrayList<>();
        List<LineRiskConstructionExcel> lneRiskDetailConstructionExcel = new ArrayList<>();
        List<LineRiskDefaultExcel> lineRiskDetailDefaultExcel = new ArrayList<>();

        for (LineRiskDTO lineRiskDTO : list) {
            if (lineRiskDTO.getLineRiskDetailBuilding() != null) {
                LineRiskBuildingExcel lineRiskBuildingExcel = BeanUtil.toBean(lineRiskDTO.getLineRiskDetailBuilding(), LineRiskBuildingExcel.class);
                lineRiskBuildingExcel.setTitle(lineRiskDTO.getTitle());
                lineRiskBuildingExcel.setEquipmentName(lineRiskDTO.getEquipmentName());
                lineRiskBuildingExcel.setLineRiskPartStr(lineRiskDTO.getLineRiskPartStr());
                lineRiskBuildingExcel.setFollowDeptName(lineRiskDTO.getFollowDeptName());
                lineRiskBuildingExcel.setRiskType(lineRiskDTO.getRiskType());
                lineRiskBuildingExcel.setRiskKeyword(lineRiskDTO.getRiskKeyword());
                lineRiskBuildingExcel.setRiskLevel(lineRiskDTO.getRiskLevel());
                lineRiskBuildingExcel.setDescr(lineRiskDTO.getDescr());
                lineRiskBuildingExcel.setLineRiskMeasureStr(lineRiskDTO.getLineRiskMeasureStr(controlMeasuresMap));
                lineRiskDetailBuildingExcel.add(lineRiskBuildingExcel);
            } else if (lineRiskDTO.getLineRiskDetailConstruction() != null) {
                LineRiskConstructionExcel lineRiskConstructionExcel = BeanUtil.toBean(lineRiskDTO.getLineRiskDetailConstruction(), LineRiskConstructionExcel.class);
                lineRiskConstructionExcel.setTitle(lineRiskDTO.getTitle());
                lineRiskConstructionExcel.setEquipmentName(lineRiskDTO.getEquipmentName());
                lineRiskConstructionExcel.setLineRiskPartStr(lineRiskDTO.getLineRiskPartStr());
                lineRiskConstructionExcel.setFollowDeptName(lineRiskDTO.getFollowDeptName());
                lineRiskConstructionExcel.setRiskType(lineRiskDTO.getRiskType());
                lineRiskConstructionExcel.setRiskKeyword(lineRiskDTO.getRiskKeyword());
                lineRiskConstructionExcel.setRiskLevel(lineRiskDTO.getRiskLevel());
                lineRiskConstructionExcel.setDescr(lineRiskDTO.getDescr());
                lineRiskConstructionExcel.setLineRiskMeasureStr(lineRiskDTO.getLineRiskMeasureStr(controlMeasuresMap));
                lneRiskDetailConstructionExcel.add(lineRiskConstructionExcel);
            } else {
                LineRiskDefaultExcel lineRiskDefaultExcel = new LineRiskDefaultExcel();
                if (lineRiskDTO.getLineRiskDetailDefault() != null){
                    lineRiskDefaultExcel = BeanUtil.toBean(lineRiskDTO.getLineRiskDetailDefault(), LineRiskDefaultExcel.class);
                }
                lineRiskDefaultExcel.setTitle(lineRiskDTO.getTitle());
                lineRiskDefaultExcel.setEquipmentName(lineRiskDTO.getEquipmentName());
                lineRiskDefaultExcel.setLineRiskPartStr(lineRiskDTO.getLineRiskPartStr());
                lineRiskDefaultExcel.setFollowDeptName(lineRiskDTO.getFollowDeptName());
                lineRiskDefaultExcel.setRiskType(lineRiskDTO.getRiskType());
                lineRiskDefaultExcel.setRiskKeyword(lineRiskDTO.getRiskKeyword());
                lineRiskDefaultExcel.setRiskLevel(lineRiskDTO.getRiskLevel());
                lineRiskDefaultExcel.setDescr(lineRiskDTO.getDescr());
                lineRiskDefaultExcel.setLineRiskMeasureStr(lineRiskDTO.getLineRiskMeasureStr(controlMeasuresMap));
                lineRiskDetailDefaultExcel.add(lineRiskDefaultExcel);
            }

        }
        RiskStringStringConvertor riskStringStringConvertor = new RiskStringStringConvertor();
        RiskAutoConvertor riskAutoConvertor = new RiskAutoConvertor();
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
                .withTemplate(classPathResource.getInputStream())
                .registerConverter(riskStringStringConvertor)
                .registerConverter(riskAutoConvertor)
                .needHead(false)
                .build();
        WriteSheet buildingSheet = EasyExcel.writerSheet(0, "违规建筑风险台账")
                .head(LineRiskBuildingExcel.class)
                .build();
        excelWriter.write(lineRiskDetailBuildingExcel, buildingSheet);
        WriteSheet constructionSheet = EasyExcel.writerSheet(1, "施工风险台账")
                .head(LineRiskConstructionExcel.class)
                .build();
        excelWriter.write(lneRiskDetailConstructionExcel, constructionSheet);
        WriteSheet defaultSheet = EasyExcel.writerSheet(2, "其他风险台账")
                .head(LineRiskDefaultExcel.class)
                .build();
        excelWriter.write(lineRiskDetailDefaultExcel, defaultSheet);
        excelWriter.finish();
    }

    @Override
    public Response<Object> updateState(@RequestBody RedirectQuery redirectQuery) {
        LineRiskDTO lineRiskDTO = JSON.parseObject(redirectQuery.getFormVariables(), LineRiskDTO.class);
        if (redirectQuery.getOperation() == 16) {
            // 如果是废弃，状态改为草稿，并删除流程
            ADOConnection.runTask(getCurrDs(), lineRiskService, "updateStatus", Boolean.class, redirectQuery.getDataId(), LineRiskConstant.Status.DRAFT);
            workFlowHandler.delete(redirectQuery.getDataId());
        } else {
            ADOConnection.runTask(getCurrDs(), lineRiskService, "submit", Boolean.class, lineRiskDTO, redirectQuery.getCurNodeCode());
        }
        return Response.success();
    }

}
